package com.orcamento.entity;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.AttributeOverride;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.orcamento.entity.enums.InvoiceStatusEnum;
import com.orcamento.entity.model.Payment;
import com.orcamento.util.Money;
import com.orcamento.util.Period;

@Entity
@Table(name="Fatura")
public class Invoice {

	@Id
	@SequenceGenerator(name="invoice_id", sequenceName="invoice_id")
	@GeneratedValue(generator="invoice_id", strategy=GenerationType.AUTO)
	@Column(name="IDFatura")
	private Long id;
	@Column(name="StMes", nullable=false)
	private Integer month;
	@Column(name="StAno", nullable=false)
	private Integer year;
	@Enumerated(EnumType.STRING)
	@Column(name="EnStatus", nullable=false)
	private InvoiceStatusEnum status;
	@Embedded
	@AttributeOverride(name="value", column=@Column(name="FoLimite", nullable=false))
	private Money limit;
	
	@ManyToOne(targetEntity=CreditCard.class)
	@JoinColumn(name="IDCartaoCredito", referencedColumnName="IDCartaoCredito", nullable=false)
	private CreditCard creditCard;
	@ManyToOne(targetEntity=Account.class)
	@JoinColumn(name="IDConta", referencedColumnName="IDPatrimonio", nullable=false)
	private Account account;
	
	@OneToMany(mappedBy="invoice")
	private List<Spent> spents = new ArrayList<Spent>();
	@OneToMany(mappedBy="invoice")
	private List<Installment> installments = new ArrayList<Installment>();
	
	@Transient
	private Invoice next;
	@Transient
	private Invoice previous;
	
	public Invoice() {
		this.status = InvoiceStatusEnum.ABERTO;
	}
	
	public Invoice(Integer month, Integer year, CreditCard creditCard) {
		this();
		this.month = month;
		this.year = year;
		this.creditCard = creditCard;
	}
	
	public List<Payment> getPayments() {
		List<Payment> payments = new ArrayList<Payment>();
		for( Spent spent : spents ) {
			if( spent.isCashCreditCardPayment() ) {
				payments.add( spent.toPayment() );
			}
		}
		
		for( Installment installment : installments ) {
			payments.add( installment.toPayment() );
		}
		return payments;
	}
	
	public Money getTotal() {
		Money total = new Money();
		for( Spent spent : spents ) {
			if( spent.isCashCreditCardPayment() ) {
				total = total.plus( spent.getValue() );
			}
		}
		
		for( Installment installment : installments ) {
			total = total.plus( installment.getValue() );
		}
		return total;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((month == null) ? 0 : month.hashCode());
		result = prime * result + ((year == null) ? 0 : year.hashCode());
		return result;
	}

	
	@Override
	public boolean equals(Object object) {
		if( object == null ) {
			return false;
		}
		if( object.getClass() != getClass() ) {
			return false;
		}
		
		Invoice invoice = (Invoice) object;
		if( month == null || year == null || invoice.month == null || invoice.year == null ) {
			return false;
		}
		
		return month.equals( invoice.month ) && year.equals( invoice.year ); 
	}
	
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public Integer getMonth() {
		return month;
	}
	public void setMonth(Integer month) {
		this.month = month;
	}
	public Integer getYear() {
		return year;
	}
	public void setYear(Integer year) {
		this.year = year;
	}
	public InvoiceStatusEnum getStatus() {
		return status;
	}
	public void setStatus(InvoiceStatusEnum status) {
		this.status = status;
	}
	public CreditCard getCreditCard() {
		return creditCard;
	}
	public void setCreditCard(CreditCard creditCard) {
		this.creditCard = creditCard;
	}
	public List<Spent> getSpents() {
		return spents;
	}
	public void setSpents(List<Spent> spents) {
		this.spents = spents;
	}
	public Money getLimit() {
		return limit;
	}
	public void setLimit(Money limit) {
		this.limit = limit;
	}

	public Invoice getNext() {
		return next;
	}

	public void setNext(Invoice next) {
		this.next = next;
	}

	public Invoice getPrevious() {
		return previous;
	}

	public void setPrevious(Invoice previous) {
		this.previous = previous;
	}

	public List<Installment> getInstallments() {
		return installments;
	}

	public void setInstallments(List<Installment> installments) {
		this.installments = installments;
	}

	public boolean isPayable() {
		return InvoiceStatusEnum.FECHADO.equals( status );
	}

	public Account getAccount() {
		return account;
	}

	public void setAccount(Account account) {
		this.account = account;
	}

	public Period getPeriod() {
		return new Period( year, month );
	}

}
